//
//  Moya+Extension.swift
//  CCMoney_swift
//
//  Created by JKHuang on 2018/11/27.
//  Copyright © 2018 JKHuang. All rights reserved.
//

import UIKit
import Moya
import ObjectMapper
import RxCocoa
import RxSwift
import SVProgressHUD

extension TargetType {
    
    var baseUrl: URL {
        return URL(string: CCMServerDomain)!
    }
    
    var sampleData: Data {
        
        return "Half measures are as bad as nothing at all.".data(using: String.Encoding.utf8)!
    }
    
    var validate: Bool { return true }
    
    // The headers to be used in the request.
    //设置头部
    var headers: [String: String]? {
        
        return ["Authorization": UserDefaults.standard.object(forKey: CCMTokenKey) as? String ?? ""]
    }
    
}

extension Response {
    
    public func filterSuccessfulStatusCodes() throws -> Response {
        return try filter(statusCodes: 200...800)
    }
    
    public func filterSuccessfulStatusAndRedirectCodes() throws -> Response {
        return try filter(statusCodes: 200...800)
    }
    
    var status: Int {
        get {
            do {
                let optionDictionary = try self.mapJSON() as? Dictionary<String, Any>
                guard let dictionary = optionDictionary else {
                    throw MoyaError.jsonMapping(self)
                }
                let optionStatus = dictionary[CCMStatusKey] as? Int
                if let status = optionStatus {
                    return status
                }
                return CCMStatusError
            }
            catch {
                return CCMStatusError
            }
        }
    }
    
    var message: String {
        get {
            do {
                let optionDictionary = try self.mapJSON() as? Dictionary<String, Any>
                guard let dictionary = optionDictionary else {
                    throw MoyaError.jsonMapping(self)
                }
                let optionmessage = dictionary[CCMessagekey] as? String
                if let message = optionmessage {
                    return message
                }
                return ""
            }
            catch {
                return ""
            }
        }
    }
    
    var content: Any? {
        get {
            do {
                let optionDictionary = try self.mapJSON() as? Dictionary<String, Any>
                guard let dictionary = optionDictionary else {
                    throw MoyaError.jsonMapping(self)
                }
                if status == 0{
                    let optionData = dictionary[CCMDataKey]
                    if let data = optionData {
                        return data
                    }
                }
                return nil
            }
            catch {
                return nil
            }
        }
    }
    
    var responseData: Any? {
        get {
            do {
                let optionDictionary = try self.mapJSON() as? Dictionary<String, Any>
                guard let dictionary = optionDictionary else {
                    throw MoyaError.jsonMapping(self)
                }
                let optionData = dictionary["data"]
                if let data = optionData {
                    return data
                }
                return nil
            }
            catch {
                return nil
            }
        }
    }
    
    func mapDictionary() -> HHResponse<Dictionary<String, Any>> {
        if status != 0 {
            SVProgressHUD.showError(withStatus: message)
            return HHResponse<Dictionary<String, Any>>.Failed(HHError.RequestError)
        }
        
        if message.count > 0 {
            SVProgressHUD.showSuccess(withStatus: message)
        }
        
        if content is Dictionary<String, Any> {
            return HHResponse.Success(content as! Dictionary<String, Any>)
        }
        else {
            return HHResponse.Success(Dictionary<String, Any>())
        }
    }
    
    func mapObject<T: BaseMappable>(_ type: T.Type) -> HHResponse<T> {
        if status != 0 {
            SVProgressHUD.showError(withStatus: message)
            return HHResponse<T>.Failed(HHError.RequestError)
        }
        
        if message.count > 0 {
            SVProgressHUD.showSuccess(withStatus: message)
        }
        
        guard let object = Mapper<T>().map(JSONObject: content) else {
            return HHResponse<T>.Failed(MoyaError.jsonMapping(self))
        }
        return HHResponse.Success(object)
    }
    
    func mapArray<T: BaseMappable>(_ type: T.Type) -> HHResponse<[T]> {
        if status != 0 {
            SVProgressHUD.showError(withStatus: message)
            return HHResponse<[T]>.Failed(HHError.RequestError)
        }
        
        if message.count > 0 {
            SVProgressHUD.showSuccess(withStatus: message)
        }
        
        guard let array = Mapper<T>().mapArray(JSONObject: content) else {
            return HHResponse<[T]>.Failed(MoyaError.jsonMapping(self))
        }
        return HHResponse.Success(array)
    }
    
    func mapList<T: BaseMappable>(_ type: T.Type) -> HHResponse<[T]> {
        if status != 0 {
            SVProgressHUD.showError(withStatus: message)
            return HHResponse<[T]>.Failed(HHError.RequestError)
        }
        
        if message.count > 0 {
            SVProgressHUD.showSuccess(withStatus: message)
        }
        
        let data = content as? Dictionary<String, Any> ?? Dictionary()
        guard let array = Mapper<T>().mapArray(JSONObject: data["data"]) else {
            return HHResponse<[T]>.Failed(MoyaError.jsonMapping(self))
        }
        return HHResponse.Success(array)
    }
    
}

extension ObservableType where E == Response {
    
    func mapDictionary() -> Observable<HHResponse<Dictionary<String, Any>>> {
        return flatMap({ response -> Observable<HHResponse<Dictionary<String, Any>>> in
            return Observable.just(response.mapDictionary())
        })
    }
    
    func mapObject<T: BaseMappable>(_ type: T.Type) -> Observable<HHResponse<T>> {
        return flatMap({ response -> Observable<HHResponse<T>> in
            return Observable.just(response.mapObject(T.self))
        })
    }
    
    func mapArray<T: BaseMappable>(_ type: T.Type) -> Observable<HHResponse<[T]>> {
        return flatMap { response -> Observable<HHResponse<[T]>> in
            return Observable.just(response.mapArray(T.self))
        }
    }
    
    func mapList<T: BaseMappable>(_ type: T.Type) -> Observable<HHResponse<[T]>> {
        return flatMap { response -> Observable<HHResponse<[T]>> in
            print(response)
            return Observable.just(response.mapList(T.self))
        }
    }
    
    
}
